﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace LSocket.Client {
    public class LNet {
        Socket sock;
        Socket serverSock;
        string serverIP = "127.0.0.1";
        int localPort = 10001;
        SocketAsyncEventArgs connectSAEA;
        SocketAsyncEventArgs sendSAEA;
        SocketAsyncEventArgs receiveSAEA;
        EventWaitHandle waitHandle = new AutoResetEvent(false);
        //internal byte[] ReceiveBuffer;
        //internal byte[] SendBuffer;

        static ConcurrentQueue<byte[]> ReceivedMessage = new ConcurrentQueue<byte[]>();
        Thread CheckNewCmd;

        public LNet() {
            byte[] ReceiveBuffer = new byte[500000];
            byte[] SendBuffer = new byte[500000];

            connectSAEA = new SocketAsyncEventArgs();
            connectSAEA.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(serverIP), localPort);
            connectSAEA.Completed += new EventHandler<SocketAsyncEventArgs>(connectSAEA_Completed);

            sendSAEA = new SocketAsyncEventArgs();
            sendSAEA.SetBuffer(SendBuffer, 0, SendBuffer.Length);
            sendSAEA.RemoteEndPoint = connectSAEA.RemoteEndPoint;
            receiveSAEA = new SocketAsyncEventArgs();
            receiveSAEA.SetBuffer(SendBuffer, 0, SendBuffer.Length);
            receiveSAEA.RemoteEndPoint = connectSAEA.RemoteEndPoint;
            receiveSAEA.Completed += new EventHandler<SocketAsyncEventArgs>(receiveSAEA_Completed);

            sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            sock.ConnectAsync(connectSAEA);
        }

        void connectSAEA_Completed(object sender, SocketAsyncEventArgs e) {
            if (e.SocketError == SocketError.Success) {
                serverSock = e.ConnectSocket;

                CheckNewCmd = new Thread(DealCmdQueue);
                CheckNewCmd.IsBackground = true;
                CheckNewCmd.Start();

                StartReceive();
            }
            else {
                Console.WriteLine("连接服务器失败！");
                serverSock = null;
            }
        }

        void StartReceive() {
            bool willRaiseEvent = sock.ReceiveAsync(receiveSAEA);
            if (!willRaiseEvent) {
                receiveSAEA_Completed(null, receiveSAEA);
            }
        }

        private void receiveSAEA_Completed(object sender, SocketAsyncEventArgs e) {
            if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) {
                byte[] cmd = new byte[e.BytesTransferred];
                Array.Copy(e.Buffer, 0, cmd, 0, cmd.Length);
                ReceivedMessage.Enqueue(cmd);
                waitHandle.Set();
                StartReceive();
            }
            else {
                Console.WriteLine("服务器断开了连接");
                LSocketManager.CallOnConnectionClosed();
            }
        }

        private void DealCmdQueue() {
            byte[] cmd = null;
            while (!LSocketManager.isQuit) {
                waitHandle.WaitOne();
                if (ReceivedMessage.TryDequeue(out cmd)) {
                    LSocketManager.CallOnReceived(cmd);
                }
            }
        }

        internal void Send(byte[] cmd) {
            Array.Clear(sendSAEA.Buffer, 0, sendSAEA.Buffer.Length);
            cmd.CopyTo(sendSAEA.Buffer, 0);
            sendSAEA.SetBuffer(0, cmd.Length);
            sock.SendAsync(sendSAEA);
        }

    }


}
